/*
* JSA
*
* JSA is a light-weight framework, which consists of following parts:
* factory method providing prototypal inheritance for modules
* jsa.BaseAbstract and jsa.WidgetAbstract classes, bringing
*   YUI widget experience (http://yuilibrary.com/yui/docs/widget/) into your application
* jsa.Hooks allowing to assign factory hooks (e.g. interfaces, mixins, type hinting control)
*
* JSA can be exploited over any JS-library. You just have to specify a callback for querySelector
* function of the library you utilize.
*
* Example:
* var AbstractModule = function () {
*   var privateProp = "..";
*   return {
*       extend: jsa.BaseAbstract
*       // module public constructor
*       init: function () {
*       },
*       publicProp: "..."
*   };
* },
* ConcreteModule = function(optionalArg) {
*   return {
*       extend: AbstractModule
*   };
* },
* o = ConcreteModule.makeInstance(optionalArg);
* o instanceof ConcreteModule === true
* o instanceof AbstractModule === true
* o instanceof jsa.BaseAbstract === true
*
* @package JSA
* @author sheiko
* @version jsa.js, v 2.0
* @license MIT
* @copyright (c) Dmitry Sheiko http://www.dsheiko.com
* Code style: http://docs.jquery.com/JQuery_Core_Style_Guidelines
*/
var jsa = jsa || {};
(function( jsa, undefined ) {
    /**
     * Configure your own querySelector function
     * @param string selector
     * @param object context (optional)
     */
    jsa.querySelectorFn = jsa.querySelectorFn || window.jQuery;
    /**
     * Helper
     */
    jsa.isArray = function ( obj ) {
        return ( Object.prototype.toString.call( obj ) === '[object Array]' );
    };
    /**
     * Factory hooks manager
     * Any hook assigned by the object will be invoked right after factory creates a new instance
     */
    jsa.Hook = jsa.Hook || []; // If hooks defined were externally before now
    jsa.Hook = (function(extHooks) {
        var hooks = extHooks, isComplete = false;
        return {
            setComplete: function () {
                isComplete = true;
            },
            reset: function () {
                hooks = [];
                isComplete = false;
            },
            push : function( fn ) {
                hooks.push( fn );
            },
            invokeAll: function( instance, args ) {
                var len = hooks.length, i = 0;
                for ( ; i < len; i++ ) {
                    hooks[ i ]( instance, args );
                }
            }
        }
    }(jsa.Hook));

    /**
     * Base is designed to be a low-level foundation class from which other
     * classes can be derived. It tries to invoke automatically init, renderUI, syncUI methods
     * of every class the last successor class inherit
     **/
     jsa.BaseAbstract = function () {
         // Add bootstrap
         jsa.Hook.push(function ( instance ) {
             var bootstrapMethods = [ 'init', 'renderUI', 'syncUI' ],
                 i = 0,
                 len = bootstrapMethods.length;
             for (; i < len; i++) {
                 instance[bootstrapMethods[ i ]] && instance [bootstrapMethods[ i ]]();
             }

         });
         // Reached the very base object of the hirerarhy. From that moment if any hook to be added
         // it comes from different hirerarhy and, thus, hooks array must be reset
         jsa.Hook.setComplete();
         return {}
     }

     /**
     * Widget is the foundation class from which all widgets are derived.
     * It provides the following pieces of core functionality on top of
     * what BaseAbstract already provides:
     *  - A common set of widget attributes
     *  - Consistent markup generation support
     */
    jsa.WidgetAbstract = function ( settings ) {
        if (settings === undefined || settings.boundingBox === undefined) {
            throw new TypeError( "Widget derivative is expected to get an argument, "
                + "which contains settings object with boundingBox property" );
        }
        jsa.Hook.push(function ( instance ) {
             instance.settings = settings;
             instance.node = {};
             instance.node.boundingBox = jsa.querySelectorFn( settings.boundingBox );
             if ( instance.HTML_PARSER ) {
                 for ( var i in instance.HTML_PARSER) {
                     if (instance.HTML_PARSER.hasOwnProperty( i )) {
                        instance.node[ i ] = jsa.querySelectorFn( instance.HTML_PARSER[ i ],
                            instance.node.boundingBox );
                     }
                };
            }
         });
         return {
             extend: jsa.BaseAbstract
         }
    }

    /**
     * Factory method implementing prototypal inheritance for modules
     * Arguments of the method are being passed to the context constructor
     */
    Function.prototype.createInstance = function () {
        var key, module = this, members = module.apply( this, arguments ),
            instance, Fn = function () {};
        members.extend && ( module.prototype =
            members.extend.createInstance.apply( members.extend, arguments ) );
        Fn.prototype = module.prototype; // Link to the supertype
        for ( key in members ) { // Mix in members
            if ( members.hasOwnProperty( key ) ) {
                Fn.prototype[ key ] = members[ key ];
            }
        }
        instance = new Fn();
        jsa.Hook.invokeAll( instance, arguments );
        return instance;
    };

})( jsa );
